package com.woniu.controller;

import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.codec.multipart.FilePart;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;

import com.woniu.been.entity.CourseCategories;
import com.woniu.been.entity.CourseChapters;
import com.woniu.been.entity.Courses;
import com.woniu.been.entity.Video;
import com.woniu.service.CourseCategoriesService;
import com.woniu.service.CourseChaptersService;
import com.woniu.service.CoursesService;
import com.woniu.service.MinioService;
import com.woniu.service.VideoService;
import com.woniu.utils.Result;

import lombok.extern.slf4j.Slf4j;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;

@Slf4j
@RestController
@RequestMapping("/api/video")
@CrossOrigin(origins = {"http://localhost:5174", "http://localhost:5173"}, allowCredentials = "true")
public class VideoController {
    @Autowired
    private MinioService minioService;

    @Autowired
    private VideoService videoService;

    @Autowired
    private CourseCategoriesService courseCategoriesService;

    @Autowired
    private CourseChaptersService courseChaptersService;

    @Autowired
    private CoursesService coursesService;

    /**
     * 单文件上传接口，支持四级课程层级结构
     * 路径：/api/video/upload/{mainCategoryId}/{subCategoryId}/{chapterId}/{courseId}
     *
     * @param file FilePart对象，包含上传的文件
     * @param mainCategoryId 课程大类ID
     * @param subCategoryId 课程小类ID
     * @param chapterId 章节ID
     * @param courseId 具体课程ID
     * @param createName 创建人姓名
     * @return 包含文件名、URL和视频ID的响应
     */
    @PostMapping(value = "/upload/{mainCategoryId}/{subCategoryId}/{chapterId}/{courseId}",
            consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public Mono<ResponseEntity<Result<Map<String, Object>>>> uploadVideo(
            @RequestPart(value = "file", required = false) FilePart file,
            @PathVariable Integer mainCategoryId,
            @PathVariable Integer subCategoryId,
            @PathVariable Integer chapterId,
            @PathVariable Integer courseId,
            @RequestPart(value = "createName", required = false) String createName) {

        log.info("开始上传视频文件: {}", file.filename());
        log.info("层级信息: mainCategoryId={}, subCategoryId={}, chapterId={}, courseId={}",
                mainCategoryId, subCategoryId, chapterId, courseId);

        // 验证文件类型
        MediaType contentType = file.headers().getContentType();
        if (contentType == null || !contentType.toString().startsWith("video/")) {
            return (Mono<ResponseEntity<Result<Map<String, Object>>>>) (Mono<?>) Mono.just(ResponseEntity.badRequest().body(Result.fail("只允许上传视频文件")));
        }

        // 验证层级关系的有效性
        return validateCourseHierarchy(mainCategoryId, subCategoryId, chapterId, courseId)
                .flatMap(validationResult -> {
                    if (!validationResult.isValid()) {
                        return (Mono<ResponseEntity<Result<Map<String, Object>>>>) (Mono<?>) Mono.just(ResponseEntity.badRequest().body(Result.fail("层级关系验证失败：" + validationResult.getErrorMessage())));
                    }

                    // 获取层级名称用于构建文件路径
                    String mainCategoryName = validationResult.getMainCategoryName();
                    String subCategoryName = validationResult.getSubCategoryName();
                    String chapterName = validationResult.getChapterName();
                    String courseName = validationResult.getCourseName();

                    // 构建文件路径：课程大类/课程小类/章节/课程/文件名
                    String filePath = String.format("%s/%s/%s/%s",
                            mainCategoryName, subCategoryName, chapterName, courseName);

                    return minioService.uploadVideo(file, mainCategoryName, subCategoryName, chapterName, courseName)
                            .flatMap(fileName -> {
                                String videoUrl = minioService.getVideoUrl(fileName);
                                String fixedUrl = videoUrl.replace("http://192.168.75.1:9000", "http://a8b26d56.natappfree.cc");
                                // 创建视频信息对象
                                Video video = new Video();
                                video.setCourseId(courseId);
                                video.setChapterId(chapterId);
                                video.setFileName(fileName);
                                video.setTitle(file.filename());
                                video.setLink(fixedUrl);
                                video.setCreateName(createName != null ? createName : "未知用户");
                                video.setCreateTime(new Date());

                                // 将阻塞的数据库操作放入单独的线程池中执行
                                return Mono.fromCallable(() -> {
                                            log.info("保存视频元数据到数据库，文件名: {}", fileName);
                                            Video savedVideo = videoService.saveVideo(video);
                                            log.info("成功保存视频元数据，文件名: {}", fileName);
                                            return savedVideo;
                                        }).subscribeOn(Schedulers.boundedElastic())
                                        .map(savedVideo -> {
                                            log.info("视频上传成功，文件名: {}, URL: {}, VideoID: {}",
                                                    fileName, fixedUrl, savedVideo.getVideoId());

                                            Map<String, Object> responseData = new HashMap<>();
                                            responseData.put("fileName", fileName);
                                            responseData.put("url", fixedUrl);
                                            responseData.put("videoId", savedVideo.getVideoId());
                                            responseData.put("filePath", filePath);

                                            return ResponseEntity.ok(Result.success(responseData));
                                        });
                            });
                })
                .onErrorResume(e -> {
                    log.error("视频上传失败", e);
                    return (Mono<ResponseEntity<Result<Map<String, Object>>>>) (Mono<?>) Mono.just(ResponseEntity.badRequest().body(Result.fail("视频上传失败：" + e.getMessage())));
                });
    }

    /**
     * 验证课程层级关系的有效性
     */
    private Mono<ValidationResult> validateCourseHierarchy(Integer mainCategoryId, Integer subCategoryId,
                                                           Integer chapterId, Integer courseId) {
        return Mono.fromCallable(() -> {
            ValidationResult result = new ValidationResult();

            try {
                // 1. 验证课程大类是否存在且为顶级分类
                CourseCategories mainCategory = courseCategoriesService.getCategoryById(mainCategoryId);
                if (mainCategory == null) {
                    result.setValid(false);
                    result.setErrorMessage("课程大类不存在");
                    return result;
                }
                if (mainCategory.getParentCategoryId() != null) {
                    result.setValid(false);
                    result.setErrorMessage("指定的课程大类ID不是顶级分类");
                    return result;
                }
                result.setMainCategoryName(mainCategory.getCategoryName());

                // 2. 验证课程小类是否存在且属于指定的课程大类
                List<CourseCategories> subCategories = courseCategoriesService.getSubCategoriesByParentId(mainCategoryId);
                CourseCategories subCategory = subCategories.stream()
                        .filter(sc -> sc.getCategoryId().equals(subCategoryId))
                        .findFirst()
                        .orElse(null);
                if (subCategory == null) {
                    result.setValid(false);
                    result.setErrorMessage("课程小类不存在或不属于指定的课程大类");
                    return result;
                }
                result.setSubCategoryName(subCategory.getCategoryName());

                // 3. 验证章节是否存在且属于指定的课程小类
                List<CourseChapters> chapters = courseChaptersService.getChaptersBySubCategoryId(subCategoryId);
                CourseChapters chapter = chapters.stream()
                        .filter(c -> c.getChapterId().equals(chapterId))
                        .findFirst()
                        .orElse(null);
                if (chapter == null) {
                    result.setValid(false);
                    result.setErrorMessage("章节不存在或不属于指定的课程小类");
                    return result;
                }
                result.setChapterName(chapter.getChapterName());

                // 4. 验证具体课程是否存在且属于指定的章节
                List<Courses> courses = coursesService.getCoursesByChapterId(chapterId);
                Courses course = courses.stream()
                        .filter(c -> c.getCourseId().equals(courseId.longValue()))
                        .findFirst()
                        .orElse(null);
                if (course == null) {
                    result.setValid(false);
                    result.setErrorMessage("具体课程不存在或不属于指定的章节");
                    return result;
                }
                result.setCourseName(course.getCourseName());

                result.setValid(true);
                return result;

            } catch (Exception e) {
                log.error("验证课程层级关系时发生错误", e);
                result.setValid(false);
                result.setErrorMessage("验证过程中发生错误：" + e.getMessage());
                return result;
            }
        }).subscribeOn(Schedulers.boundedElastic());
    }

    /**
     * 根据课程ID获取视频列表（保持向后兼容）
     * @param courseId 课程ID
     * @param categoryName 课程大类名称 (可选)
     * @return 视频列表
     */
    @GetMapping("/course/{courseId}")
    public ResponseEntity<Result<?>> getVideosByCourseId(
            @PathVariable Integer courseId,
            @RequestParam(required = false) String categoryName) {
        try {
            List<Video> videos = videoService.getVideosByCourseIdAndFilters(courseId, categoryName);
            return ResponseEntity.ok(Result.success(videos));
        } catch (Exception e) {
            log.error("获取视频列表失败，courseId: {}, categoryName: {}", courseId, categoryName, e);
            return ResponseEntity.badRequest().body(Result.error("获取视频列表失败：" + e.getMessage()));
        }
    }

    /**
     * 根据章节ID获取视频列表
     * @param chapterId 章节ID
     * @return 视频列表
     */
    @GetMapping("/chapter/{chapterId}")
    public ResponseEntity<Result<?>> getVideosByChapterId(@PathVariable Integer chapterId) {
        try {
            List<Video> videos = videoService.getVideosByChapterId(chapterId);
            return ResponseEntity.ok(Result.success(videos));
        } catch (Exception e) {
            log.error("获取章节视频列表失败，chapterId: {}", chapterId, e);
            return ResponseEntity.badRequest().body(Result.error("获取章节视频列表失败：" + e.getMessage()));
        }
    }

    /**
     * 根据课程小类ID获取视频列表
     * @param subCategoryId 课程小类ID
     * @return 视频列表
     */
    @GetMapping("/subcategory/{subCategoryId}")
    public ResponseEntity<Result<?>> getVideosBySubCategoryId(@PathVariable Integer subCategoryId) {
        try {
            List<Video> videos = videoService.getVideosBySubCategoryId(subCategoryId);
            return ResponseEntity.ok(Result.success(videos));
        } catch (Exception e) {
            log.error("获取课程小类视频列表失败，subCategoryId: {}", subCategoryId, e);
            return ResponseEntity.badRequest().body(Result.error("获取课程小类视频列表失败：" + e.getMessage()));
        }
    }

    /**
     * 修改视频标题
     * @param videoId 视频ID
     * @param body 包含新的视频标题的Map
     * @return 成功或失败的响应
     */
    @PutMapping("/{videoId}/title")
    public ResponseEntity<Result<?>> updateVideoTitle(
            @PathVariable Integer videoId,
            @RequestBody Map<String, String> body) {
        try {
            String title = body.get("title");
            if (title == null || title.trim().isEmpty()) {
                return ResponseEntity.badRequest().body(Result.error("视频标题不能为空"));
            }
            boolean success = videoService.updateVideoTitle(videoId, title);
            if (success) {
                return ResponseEntity.ok(Result.success("视频标题更新成功"));
            } else {
                return ResponseEntity.badRequest().body(Result.error("更新视频标题失败：视频ID不存在或数据未改变"));
            }
        } catch (Exception e) {
            log.error("更新视频标题失败，videoId: {}", videoId, e);
            return ResponseEntity.badRequest().body(Result.error("更新视频标题失败：" + e.getMessage()));
        }
    }

    /**
     * 删除单个视频文件和数据库记录
     * @param fileName 视频在MinIO中的完整路径（objectName）
     * @return 删除成功或失败的响应
     */
    @DeleteMapping("/delete")
    public ResponseEntity<Result<?>> deleteVideo(@RequestParam String fileName) {
        try {
            String decodedFileName = URLDecoder.decode(fileName, StandardCharsets.UTF_8);
            log.info("开始删除视频文件: {}", decodedFileName);

            boolean success = videoService.deleteVideoByFileName(decodedFileName);
            if (success) {
                log.info("视频文件和数据库记录删除成功: {}", decodedFileName);
                return ResponseEntity.ok(Result.success("视频删除成功"));
            } else {
                return ResponseEntity.badRequest().body(Result.error("删除视频失败：数据库记录删除失败或文件不存在"));
            }
        } catch (Exception e) {
            log.error("删除视频失败: {}", fileName, e);
            return ResponseEntity.badRequest().body(Result.error("删除视频失败：" + e.getMessage()));
        }
    }

    /**
     * 批量删除视频文件和数据库记录
     * @param body 包含要删除的文件名列表的Map
     * @return 批量删除成功或失败的响应
     */
    @PostMapping("/deleteBatch")
    public ResponseEntity<Result<?>> deleteBatch(@RequestBody Map<String, List<String>> body) {
        try {
            List<String> fileNames = body.get("fileNames");
            if (fileNames == null || fileNames.isEmpty()) {
                return ResponseEntity.badRequest().body(Result.error("文件列表不能为空"));
            }

            boolean success = videoService.deleteVideosByFileNames(fileNames);
            if (success) {
                return ResponseEntity.ok(Result.success("批量删除视频成功"));
            } else {
                return ResponseEntity.badRequest().body(Result.error("批量删除视频失败：部分文件删除失败"));
            }
        } catch (Exception e) {
            log.error("批量删除视频失败", e);
            return ResponseEntity.badRequest().body(Result.error("批量删除视频失败：" + e.getMessage()));
        }
    }

    /**
     * 验证结果内部类
     */
    private static class ValidationResult {
        private boolean valid;
        private String errorMessage;
        private String mainCategoryName;
        private String subCategoryName;
        private String chapterName;
        private String courseName;

        // Getters and Setters
        public boolean isValid() { return valid; }
        public void setValid(boolean valid) { this.valid = valid; }

        public String getErrorMessage() { return errorMessage; }
        public void setErrorMessage(String errorMessage) { this.errorMessage = errorMessage; }

        public String getMainCategoryName() { return mainCategoryName; }
        public void setMainCategoryName(String mainCategoryName) { this.mainCategoryName = mainCategoryName; }

        public String getSubCategoryName() { return subCategoryName; }
        public void setSubCategoryName(String subCategoryName) { this.subCategoryName = subCategoryName; }

        public String getChapterName() { return chapterName; }
        public void setChapterName(String chapterName) { this.chapterName = chapterName; }

        public String getCourseName() { return courseName; }
        public void setCourseName(String courseName) { this.courseName = courseName; }
    }
}